/* 
* Based on code by:
* Code by NomNom (24 Aug 2010)
* modified by Bruceoutdoors(2 Aug 2012)
* can be found at http://forum.codecall.net/topic/58137-java-mini-paint-program/#axzz2FLCNDNHI
*/

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

import libsvm.*;
public class DigitReader
{    
	static svm_model model;
    public static void createGUI(svm_model svmmodel)
    {
    	model = svmmodel;
    	PaintWindow frame = new PaintWindow();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setVisible(true);
    }
}

class PaintWindow extends JFrame
{   
    public PaintWindow()
    {   	
        setTitle("Digit Reader");
        setSize(350, 308);
            
        panel = new JPanel();
        drawPad = new PadDraw();
        drawPad.setMinimumSize(new Dimension(28,28));
        drawPad.setPreferredSize(new Dimension(224,224));
        drawPad.setMaximumSize(new Dimension(224,224));
        drawPad.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        JPanel panel2 = new JPanel();
        panel.setPreferredSize(new Dimension(64, 64));
        
        //Creates a new container
        Container content = this.getContentPane();
        content.setLayout(new BorderLayout());
        content.setLayout(new BoxLayout(content, BoxLayout.LINE_AXIS));
        
        //sets the panel to the left, padDraw in the center
        content.add(panel);
        content.add(drawPad);
        content.add(panel2);
        
        //creates the clear button
        JButton clearButton = new JButton("Clear");
        clearButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                drawPad.clear();
                result.setText("Digit: ");
            }
        });
        
        //creates the read button
        JButton readButton = new JButton("Read");
        readButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String result = drawPad.read();
                setResult(result);
            }
        });
        
        result = new JTextArea("Digit: ");
        
        panel.add(clearButton);
        panel.add(readButton);
        panel.add(result);
    }
    
    public void setResult(String resultText) {
    	result.setText(resultText);
    }
    
    private JPanel panel;
    private PadDraw drawPad;
    private JTextArea result;
}

class PadDraw extends JComponent
{
    //this is gonna be your image that you draw on
    Image image;
    //this is what we'll be using to draw on
    Graphics2D graphics2D;
    //these are gonna hold our mouse coordinates
    int currentX, currentY, oldX, oldY;
    
    public PadDraw()
    {
        setDoubleBuffered(false);
        addMouseListener(new MouseAdapter()
        {
            //if the mouse is pressed it sets the oldX & oldY
            //coordinates as the mouses x & y coordinates
            public void mousePressed(MouseEvent e)
            {
                oldX = e.getX();
                oldY = e.getY();
            }
        });
        
        addMouseMotionListener(new MouseMotionAdapter()
        {
            //while the mouse is dragged it sets currentX & currentY as the mouses x and y
            //then it draws a line at the coordinates
            //it repaints it and sets oldX and oldY as currentX and currentY
            public void mouseDragged(MouseEvent e)
            {
                currentX = e.getX();
                currentY = e.getY();
                
                graphics2D.setStroke(new BasicStroke(24, 1, 2));
                graphics2D.drawLine(oldX, oldY, currentX, currentY);
                repaint();
                
                oldX = currentX;
                oldY = currentY;
            }
        });
    }
    
    //this is the painting bit
    //if it has nothing on it then
    //it creates an image the size of the window
    //sets the value of Graphics as the image
    //sets the rendering
    //runs the clear() method
    //then it draws the image
    public void paintComponent(Graphics g)
    {
        if(image == null)
        {
            image = createImage(getSize().width, getSize().height);
            graphics2D = (Graphics2D)image.getGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            clear();
        }
        
        g.drawImage(image, 0, 0, null);
    }
    
    //this is the clear
    //it sets the colors as white
    //then it fills the window with white
    //thin it sets the color back to black
    public void clear()
    {
        graphics2D.setPaint(Color.white);
        graphics2D.fillRect(0, 0, getSize().width, getSize().height);
        graphics2D.setPaint(Color.black);
        repaint();
    }
    
    public String read()
    {
    	try
    	{	
    		BufferedImage theImage = new BufferedImage(getSize().width, getSize().height, BufferedImage.TYPE_INT_RGB);
    		theImage.getGraphics().drawImage(image, 0 , 0, null);
    		int[][] pattern = new int[getSize().width][getSize().height];
    		for(int x=0; x!=getWidth(); x++) {
    			for(int y=0; y!=getHeight(); y++)
        		pattern[y][x] = ((theImage.getRGB(x, y) & 0xFFFFFF) ^ 0xFFFFFF) & 255 ;	
    		}
    		pattern = Processing.slantCorrection(pattern);
    		pattern = Processing.gaussianBlur(pattern, 0.5);
    		pattern = GeneralFunctions.binarize(pattern);
    		pattern = Processing.fill(pattern, 0, true, false);
    		pattern = Processing.thin(pattern, true, false);
    		pattern = Processing.normalization(pattern, 32, 32, 3);
    		
    		FeatureVector vector = new FeatureVector(8, 8, 32, 32);
    		vector.setDensityPerRegion(PatternProcessor.densityPerRegion(8, 8, pattern));
    		vector.setProfiles(FeatureExtraction.profiles(pattern, "", false, true));
//    		vector.setTopHalfPercent(PatternProcessor.percentTopHalf(pattern));
//    		vector.setLeftHalfPercent(PatternProcessor.percentLeftHalf(pattern));
//    		vector.setVerticalReflect(PatternProcessor.reflectedVertical(pattern));
//    		vector.setHorizontalReflect(PatternProcessor.reflectedHorizontal(pattern));
    		vector.setAspectRatio(FeatureExtraction.aspectRatio(pattern, false));
    		vector.setAverageDistanceFromCenter(FeatureExtraction.averageDistanceFromCenter(pattern, false));
    		
    		pattern = Processing.skeletonize(pattern, 1, false);
    		pattern = Processing.removeSoloPoints(pattern);
    		vector.setEndPoints(FeatureExtraction.findEndPoints(pattern, "", true, false));
    		double[] prob = new double[10];
    		int[] labels = DigitReader.model.label;
    		int[] order = new int[10];
    		for(int i=0; i!=10; i++) {
    			order[labels[i]] = i;
    		}
    		double result = svm.svm_predict_probability(DigitReader.model, vector.getNodes(), prob);
//    		for(int i=0; i!=10; i++) {
//    			System.out.println(i + ": " + ((double)Math.round(prob[order[i]]*100000)/1000) + "%");
//    		}
    		System.out.println(result);
    		double conf = ((double)Math.floor(prob[order[(int)result]] *1000))/10;
    		return "Digit: " + (int)result + "\n" + conf + "%";
    		
    		// Call function to read in saved file
    		// TODO
    	}
    	
    	catch(Exception e)
    	{
    	     e.printStackTrace();
    	}
    	return "";
    }
}